package com.example.science.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.example.science.dao.UserMapper;
import com.example.science.model.User;
import com.example.science.model.UserInfo;
import com.example.science.dao.UserInfoMapper;
import com.example.science.param.UserRegisterParam;
import com.example.science.service.UserInfoService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.science.util.MD5Util;
import com.example.science.util.RedisKey;
import com.example.science.util.RedisUtil;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDate;
import java.time.temporal.ChronoField;
import java.util.HashMap;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author 戴
 * @since 2024年10月21日
 */
@Transactional
@Service
public class UserInfoServiceImpl extends ServiceImpl<UserInfoMapper, UserInfo> implements UserInfoService {
    @Resource
    private RedisUtil redisUtil;
    @Resource
    private UserInfoMapper userInfoMapper;
    @Resource
    private UserMapper userMapper;

    @Resource
    private RedissonClient redissonClient;
    @Resource
    private RabbitTemplate rabbitTemplate;

    @Override
    public void userRegister(UserRegisterParam param) throws Exception {

        RLock phoneLock = redissonClient.getFairLock(RedisKey.lockPhone(param.getPhoneNumber()));
        RLock lock = redissonClient.getMultiLock(phoneLock);
        try{
            if(lock.tryLock(20, TimeUnit.SECONDS)){
                QueryWrapper<User> queryWrapper = new QueryWrapper<>();
                queryWrapper.eq("phone_number", param.getPhoneNumber());
                //queryWrapper.eq("user_role", "农户");
                User user = userMapper.selectOne(queryWrapper);
                if (user != null) {
                    throw new Exception("手机号已注册");
                }
//                String code = redisUtil.getString(RedisKey.registerCodeKey(param.getPhoneNumber()));
//                if (!param.getCode().equals(code)) {
//                    throw new Exception("验证码错误");
//                }
                user = BeanUtil.toBean(param, User.class);
                user.setUserType("农户");
                String password = MD5Util.md5(param.getUserPass(), param.getUserName());
                user.setUserPass(password);
                userMapper.insert(user);
                //注册成功，删除Redis缓存中存的验证码
                redisUtil.del(RedisKey.registerCodeKey(param.getPhoneNumber()));
            }else{
                throw new Exception("服务器繁忙");
            }
        }finally {
            lock.unlock();
        }
    }
    @Override
    public void sendRegisterCode(String mobile) throws Exception {
        //发送验证码之前先判断上一次发送的注册验证码的过期时间
        long expire = redisUtil.ttl(RedisKey.registerCodeKey(mobile));//剩余过期时间
        if (expire != -2 && expire > 240) {
            throw new Exception("请勿频繁发送验证码");
        }

        //获取当前的月份和日期 组成键记录当天的发送次数
        LocalDate now = LocalDate.now();
        int month = now.get(ChronoField.MONTH_OF_YEAR);
        int date = now.get(ChronoField.DAY_OF_MONTH);
        String key = RedisKey.userCodeNumber(mobile, month, date);
        if (redisUtil.exists(key)) {
            if (Integer.parseInt(redisUtil.getString(key)) >= 5) {
                throw new Exception("今日发送次数已超过上限");
            }
        }
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("phone_number", mobile);
        //queryWrapper.eq("user_role", "用户");
        User user = userMapper.selectOne(queryWrapper);
        if (user != null) {
            throw new Exception("手机号已存在");
        }
        HashMap<String, String> map = new HashMap<>();
        map.put("mobile", mobile);
        map.put("key", key);
        //将手机号保存到队列中，后续通过消费者取出手机号发送验证码
        rabbitTemplate.convertAndSend("send_code_phone_queue", map);
    }
}
